package com.shenmazong.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shenmazong.library.entity.TbTaskTheoryLibrary;
import com.shenmazong.manage.entity.*;
import com.shenmazong.manage.mapper.*;
import com.shenmazong.manage.service.TaskManageService;
import com.shenmazong.util.ChooseIsNull;
import com.shenmazong.util.MyTimeUtil;
import com.shenmazong.utils.ResultResponse;
import com.shenmazong.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.shenmazong.config.MqConfig.*;

/**
 *serviceImpl Qi
 */
@Service
@Slf4j
public class TaskManageServiceImpl extends ServiceImpl<TbTaskLayoutMapper, TbTaskLayout>
    implements TaskManageService {

    @Autowired
    private  TbTaskLayoutMapper  layoutMapper;
    @Autowired
    private TbTaskSubmitMapper submitMapper;
    @Autowired
    private TbMajorMapper majorMapper;
    @Autowired
    private TbStageMapper stageMapper;
    @Autowired
    private TbTaskTheoryTemplateMapper templateMapper;
    @Autowired
    private TbTaskTheoryContentMapper contentMapper;
    @Autowired
    private TbTaskClazzMapper taskClazzMapper;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate mqTemplate;

    @Override
    public ResultResponse saveTaskLayout(TbTaskLayout tbTaskLayout) {
        try {
            int i = layoutMapper.insert(tbTaskLayout);
            if(i<1){
                return ResultResponse.FAILED("新增失败");
            }
            for (Long clazzId : tbTaskLayout.getClazzIds()) {
                TbTaskClazz tbTaskClazz = new TbTaskClazz();
                tbTaskClazz.setTaskId(tbTaskLayout.getLayoutId());
                tbTaskClazz.setClazzId(clazzId);
                taskClazzMapper.insert(tbTaskClazz);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResultResponse.FAILED("新增失败");
        }

        return ResultResponse.SUCCESS(layoutMapper.selectById(tbTaskLayout.getLayoutId()));
    }

    @Override
    public ResultResponse updateTaskLayout(TbTaskLayout tbTaskLayout) {
        int i = layoutMapper.updateById(tbTaskLayout);
        if(i<1){
            return ResultResponse.FAILED("修改失败");
        }
        return ResultResponse.SUCCESS(layoutMapper.selectById(tbTaskLayout.getLayoutId()));
    }

    @Override
    public ResultResponse deleteTaskLayout(BatchChooseIdVo chooseIdVo) {
        if (ChooseIsNull.idsIsNull(chooseIdVo)){
            return ResultResponse.FAILED("未选择要删除的数据");
        }
        int i = layoutMapper.deleteBatchIds(chooseIdVo.getIds());
        if(i<1){
            return ResultResponse.FAILED("删除失败");
        }
        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse listTaskLayout(ListParamVo paramVo) {
        //非空判断
        if(paramVo.getParamMap().size()==0 || paramVo.getParamMap().get("schoolId")==null){
            return ResultResponse.FAILED("无效查询条件");
        }

        QueryWrapper<TbTaskLayout> queryWrapper = new QueryWrapper<>();

        //教师ID 标签ID 条件查询
        if(StringUtils.checkValNotNull(paramVo.getParamMap().get("teacherId"))){
            queryWrapper.lambda().eq(TbTaskLayout::getTeacherId,paramVo.getParamMap().get("teacherId"));
        }
        if(StringUtils.checkValNotNull(paramVo.getParamMap().get("labelId"))){
            queryWrapper.lambda().eq(TbTaskLayout::getLabelId,paramVo.getParamMap().get("labelId"));
        }

        //开始时间区间查询
        if(StringUtils.checkValNotNull(paramVo.getParamMap().get("minStartTime"))){
            queryWrapper.lambda().ge(TbTaskLayout::getStartTime,paramVo.getParamMap().get("minStartTime"));
        }
        if(StringUtils.checkValNotNull(paramVo.getParamMap().get("maxStartTime"))){
            queryWrapper.lambda().le(TbTaskLayout::getStartTime,paramVo.getParamMap().get("maxStartTime"));
        }

        Page<TbTaskLayout> page = new Page<>(paramVo.getCurrent(), paramVo.getSize());
        Page<TbTaskLayout> selectPage = layoutMapper.selectPage(page, queryWrapper);

        return ResultResponse.SUCCESS(selectPage);
    }

    @Override
    public ResultResponse getTaskLayout(TbTaskLayout tbTaskLayout) {
        return ResultResponse.SUCCESS(layoutMapper.selectById(tbTaskLayout.getLayoutId()));
    }

    @Override
    public ResultResponse saveTaskSubmit(TbTaskSubmit tbTaskSubmit) {
        int i = submitMapper.insert(tbTaskSubmit);
        if(i<1){
            return ResultResponse.FAILED("新增失败");
        }
        return ResultResponse.SUCCESS(submitMapper.selectById(tbTaskSubmit.getSubmitId()));
    }

    @Override
    public ResultResponse deleteTaskSubmit(BatchChooseIdVo chooseIdVo) {
        if (ChooseIsNull.idsIsNull(chooseIdVo)){
            return ResultResponse.FAILED("未选择要删除的数据");
        }
        int i = submitMapper.deleteBatchIds(chooseIdVo.getIds());
        if(i<1){
            return ResultResponse.FAILED("删除失败");
        }
        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse updateTaskSubmit(TbTaskSubmit tbTaskSubmit) {
        int i = submitMapper.updateById(tbTaskSubmit);
        if(i<1){
            return ResultResponse.FAILED("修改失败");
        }
        return ResultResponse.SUCCESS(submitMapper.selectById(tbTaskSubmit.getSubmitId()));
    }

    @Override
    public ResultResponse listTaskSubmit(ListParamVo paramVo) {
        //非空判断
        if(paramVo.getParamMap().size()==0 || paramVo.getParamMap().get("schoolId")==null){
            return ResultResponse.FAILED("无效查询条件");
        }

        //学生姓名 作业标题 标签ID 空处理
        if(StringUtils.checkValNull(paramVo.getParamMap().get("studentName"))){
            paramVo.getParamMap().put("studentName","");
        }
        if(StringUtils.checkValNull(paramVo.getParamMap().get("taskTitle"))){
            paramVo.getParamMap().put("taskTitle","");
        }
        if(StringUtils.checkValNull(paramVo.getParamMap().get("labelId"))){
            paramVo.getParamMap().put("labelId","");
        }

        //查询数据
        IPage<TaskSubmitVo> page = new Page<>(paramVo.getCurrent(), paramVo.getSize());
        IPage<TaskSubmitVo> selectPage = submitMapper.selectTaskSubmitList(page,paramVo.getParamMap());
        return ResultResponse.SUCCESS(selectPage);
    }

    @Override
    public ResultResponse getTaskSubmit(TbTaskSubmit tbTaskSubmit) {
        return ResultResponse.SUCCESS(submitMapper.selectById(tbTaskSubmit.getSubmitId()));
    }

    @Override
    public ResultResponse listAllMajor(TbMajor tbMajor) {
        //非空判断
        if(tbMajor==null || StringUtils.checkValNull(tbMajor.getCollageId())){
            return ResultResponse.FAILED("无效查询条件");
        }

        List<TbMajor> selectList = majorMapper.selectList(
                new QueryWrapper<TbMajor>().lambda().eq(TbMajor::getCollageId, tbMajor.getCollageId()));
        return ResultResponse.SUCCESS(selectList);
    }

    @Override
    public ResultResponse listStage(ListParamVo paramVo) {
        //非空判断
        if(paramVo.getParamMap().size()==0 || paramVo.getParamMap().get("schoolId")==null){
            return ResultResponse.FAILED("无效查询条件");
        }
        if(StringUtils.checkValNull(paramVo.getParamMap().get("majorId"))){
            paramVo.getParamMap().put("majorId","");
        }
        if(StringUtils.checkValNull(paramVo.getParamMap().get("courseName"))){
            paramVo.getParamMap().put("courseName","");
        }

        //查询数据
        IPage<CourseVo> page = new Page<>(paramVo.getCurrent(), paramVo.getSize());
        IPage<CourseVo> selectPage = stageMapper.selectCourseList(page,paramVo.getParamMap());
        return ResultResponse.SUCCESS(selectPage);
    }

    @Override
    public ResultResponse saveTheoryTemplate(TbTaskTheoryTemplate theoryTemplate) {
        int i = templateMapper.insert(theoryTemplate);
        if(i<1){
            return ResultResponse.FAILED("新增失败");
        }
        return ResultResponse.SUCCESS(templateMapper.selectById(theoryTemplate.getTemplateId()));
    }

    @Override
    public ResultResponse deleteTheoryTemplate(BatchChooseIdVo chooseIdVo) {
        if (ChooseIsNull.idsIsNull(chooseIdVo)){
            return ResultResponse.FAILED("未选择要删除的数据");
        }
        int i = templateMapper.deleteBatchIds(chooseIdVo.getIds());
        if(i<1){
            return ResultResponse.FAILED("删除失败");
        }
        return ResultResponse.SUCCESS();
    }

    @Override
    public ResultResponse updateTheoryTemplate(TbTaskTheoryTemplate theoryTemplate) {
        String time = MyTimeUtil.getNowTimeToString();
        theoryTemplate.setUpdateTime(time);
        int i = templateMapper.updateById(theoryTemplate);
        if(i<1){
            return ResultResponse.FAILED("修改失败");
        }
        return ResultResponse.SUCCESS(templateMapper.selectById(theoryTemplate.getTemplateId()));
    }

    @Override
    public ResultResponse listTheoryTemplate(ListParamVo paramVo) {

        //查询数据
        IPage<TbTaskTheoryTemplate> page = new Page<>(paramVo.getCurrent(), paramVo.getSize());
        IPage<TbTaskTheoryTemplate> selectPage = templateMapper.selectPage(page,null);
        return ResultResponse.SUCCESS(selectPage);
    }

    @Override
    public ResultResponse listAllTheoryTemplate() {
        return ResultResponse.SUCCESS(templateMapper.selectList(null));
    }

    @Override
    public ResultResponse listAllStage(BatchChooseIdVo chooseIdVo) {
        if (ChooseIsNull.idsIsNull(chooseIdVo)){
            return ResultResponse.FAILED("未选择数据");
        }

        List<TbStage> selectList = stageMapper.selectList(
                new QueryWrapper<TbStage>().lambda().in(TbStage::getMajorId, chooseIdVo.getIds())
        );
        return ResultResponse.SUCCESS(selectList);
    }

    @Override
    public ResultResponse saveTheoryContent(TheoryContentVo contentVo) {

        //创建存储mongo的对象
        ContentToMongo contentToMongo = new ContentToMongo();
        String nowTimeToString = MyTimeUtil.getNowTimeToString();
        contentToMongo.setCreateTime(nowTimeToString);
        contentToMongo.setUpdateTime(nowTimeToString);

        //创建存入SQL的对象
        TbTaskTheoryContent theoryContent = new TbTaskTheoryContent();
        ObjectMapper mapper = new ObjectMapper();
        ContentToMongo save = null;
        try {

            //试题内容转换格式
            List<TheoryTestVo> list = new ArrayList<>();

            for (TbTaskTheoryLibrary library : contentVo.getTheoryData()) {
                //对象格式转换
                TheoryTestVo theoryVo = new TheoryTestVo();
                theoryVo.setTheoryId(library.getTheoryId());
                theoryVo.setTheoryType(library.getTheoryType());
                theoryVo.setTheoryTitle(library.getTheoryTitle());
                theoryVo.setLevel(library.getLevel());
                theoryVo.setAnswers(library.getAnswers());
                //选项变更为集合形式
                List<OptionVo> options = new ArrayList<>();
                if(library.getTheoryType().equals("0-判断题")){
                    options.add(new OptionVo("A","正确"));
                    options.add(new OptionVo("B","错误"));
                }else {
                    if(StringUtils.checkValNotNull(library.getOption1())){
                        options.add(new OptionVo("A",library.getOption1()));
                    }
                    if(StringUtils.checkValNotNull(library.getOption2())){
                        options.add(new OptionVo("B",library.getOption2()));
                    }
                    if(StringUtils.checkValNotNull(library.getOption3())){
                        options.add(new OptionVo("C",library.getOption3()));
                    }
                    if(StringUtils.checkValNotNull(library.getOption4())){
                        options.add(new OptionVo("D",library.getOption4()));
                    }
                    if(StringUtils.checkValNotNull(library.getOption5())){
                        options.add(new OptionVo("E",library.getOption5()));
                    }
                    if(StringUtils.checkValNotNull(library.getOption6())){
                        options.add(new OptionVo("F",library.getOption6()));
                    }
                }


                theoryVo.setOptions(options);
                list.add(theoryVo);
            }

            //试题内容转为JSON字符串

            String content = mapper.writeValueAsString(list);
            contentToMongo.setContent(content);
            //存入mongo 获取返回的对象
            save = mongoTemplate.save(contentToMongo);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("数据存入MongoDB失败");
            return ResultResponse.FAILED("数据存入MongoDB失败");
        }
        //复制对象数据
        BeanUtils.copyProperties(contentVo,theoryContent);
        //把mongoID存入对象
        theoryContent.setTheoryMongo(save.getId());
        //存入对象
        int i = contentMapper.insert(theoryContent);
        if(i<1){
            return ResultResponse.FAILED("新增失败");
        }
        return ResultResponse.SUCCESS(contentMapper.selectById(theoryContent.getContentId()));
    }

    @Override
    public ResultResponse updateTheoryContent(TbTaskTheoryContent theoryContent) {
        String time = MyTimeUtil.getNowTimeToString();
        theoryContent.setUpdateTime(time);
        int i = contentMapper.updateById(theoryContent);
        if(i<1){
            return ResultResponse.FAILED("修改失败");
        }
        return ResultResponse.SUCCESS(contentMapper.selectById(theoryContent.getContentId()));
    }

    @Override
    public ResultResponse getContentByMongo(ContentToMongo content) {

        Query query = new Query(Criteria.where("_id").is(content.getId()));
        ContentToMongo contentToMongo = mongoTemplate.findOne(query, ContentToMongo.class);

        if(contentToMongo == null){
            return ResultResponse.FAILED("获取试题失败,请联系管理员");
        }

        //解析JSON字符串
        ObjectMapper mapper = new ObjectMapper();
        List<TheoryTestVo> list = null;
        try {
            list = mapper.readValue(contentToMongo.getContent(), new TypeReference<List<TheoryTestVo>>() {
            });
            for (TheoryTestVo testVo : list) {
                testVo.setAnswers(null);
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return ResultResponse.FAILED("试题解析失败,请联系管理员");
        }
        return ResultResponse.SUCCESS(list);
    }

    @Override
    public ResultResponse listTaskByClazz(TaskStudentVo studentVo) {
        //生成Redis中获取考试信息的key
        String key = "task_layout_clazz_"+studentVo.getClazzId();
        if(!redisTemplate.hasKey(key)){
            return ResultResponse.FAILED("暂无考试安排");
        }
        //读取Redis中信息 返回
        Set<String> set = redisTemplate.opsForSet().members(key);
        List<TbTaskLayout> list = new ArrayList<>();
        ObjectMapper mapper = new ObjectMapper();
        for (String layoutId : set) {
            try {
                String layoutKey = "task_layout_"+layoutId;
                String layout = redisTemplate.opsForValue().get(layoutKey);
                TbTaskLayout tbTaskLayout = mapper.readValue(layout, TbTaskLayout.class);
                list.add(tbTaskLayout);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                return ResultResponse.FAILED("考试安排获取失败");
            }
        }
        return ResultResponse.SUCCESS(list);
    }

    @Override
    public void getTaskLayoutToRedisByTiming() {
        //获取未开始考试且未展示的作业安排
        List<TbTaskLayout> layoutList = layoutMapper.selectList(
                new QueryWrapper<TbTaskLayout>().lambda().eq(TbTaskLayout::getTaskStatus, 0)
                        .eq(TbTaskLayout::getShowStatus, 0)
        );
        if(layoutList.size()==0){
            log.info("暂无需要展示的考试安排");
        }

        //获取当前时间时间戳
        long nowTime = System.currentTimeMillis();
        log.info("当前时间戳:{}",nowTime);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


        for (TbTaskLayout taskLayout : layoutList) {
            try {
                //将考试安排开始时间转为时间戳
                Date date = sdf.parse(taskLayout.getStartTime());
                long startTime = date.getTime();
                //判断时间是否小于1小时
                long remain = (startTime-nowTime)/(1000*60);
                //时间小于1小时 符合要求 放入Redis中展示
                if(remain<=60){
                    //存入消息队列处理
                    ObjectMapper mapper = new ObjectMapper();
                    try {
                        String value = mapper.writeValueAsString(taskLayout);
                        mqTemplate.convertAndSend(TASK_LAYOUT_QUEUE,value);
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.info("定时考试安排设置失败");
                    }
                    log.info("定时考试安排设置成功");
                }
            } catch (Exception e) {
                e.printStackTrace();
                log.info("定时展示考试执行错误");
            }
        }
    }

    @Override
    public ResultResponse getLayoutToRedisById(TbTaskLayout layout) {
        TbTaskLayout tbTaskLayout = layoutMapper.selectById(layout.getLayoutId());
        if(tbTaskLayout.getShowStatus()==1){
            return ResultResponse.FAILED("该考试已经展示");
        }else if (tbTaskLayout.getShowStatus()==2){
            return ResultResponse.FAILED("该考试已经结束");
        }
        //存入消息队列处理
        ObjectMapper mapper = new ObjectMapper();
        try {
            String value = mapper.writeValueAsString(tbTaskLayout);
            mqTemplate.convertAndSend(TASK_LAYOUT_QUEUE,value);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultResponse.FAILED("设置失败");
        }

        return ResultResponse.SUCCESS("设置成功");
    }

    @Override
    public ResultResponse startTask(TaskStudentVo taskStudentVo) {

        ObjectMapper mapper = new ObjectMapper();

        List<TheoryTestVo> list = null;
        try {
            //信息发送到消息队列生成 考试提交表 考试成绩表等信息
            String value = mapper.writeValueAsString(taskStudentVo);
            mqTemplate.convertAndSend(TASK_START_TEST_QUEUE,value);

            //获取考试试题
            String contentKey = "task_content_"+taskStudentVo.getLayoutId();
            if(!redisTemplate.hasKey(contentKey)){
                return ResultResponse.FAILED("获取试题失败,请联系管理员");
            }
            //解析JSON字符串
            String content = redisTemplate.opsForValue().get(contentKey);
            list = mapper.readValue(content, new TypeReference<List<TheoryTestVo>>() {
            });
            for (TheoryTestVo testVo : list) {
                testVo.setAnswers(null);
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return ResultResponse.FAILED("试题解析失败,请联系管理员");
        }

        return ResultResponse.SUCCESS(list);
    }

    @Override
    public void setTaskStartOrEnd() {
        //获取当前时间戳
        long nowTime = System.currentTimeMillis();

        //Redis存放作业开始结束时间戳的key
        String showTaskTime = "show_task_time_map";
        //取出存放的时间戳的map
        Map<Object, Object> map = redisTemplate.opsForHash().entries(showTaskTime);

        ObjectMapper mapper = new ObjectMapper();

        //获取展示状态的作业布置ID
        try {
            String showTask = "show_task";
            Set<String> set = redisTemplate.opsForSet().members(showTask);
            for (String layoutId : set) {
                //获取存储的时间戳
                String value = (String) map.get(layoutId);
                if(StringUtils.checkValNotNull(value)){
                    StartAndEndTimeVo startAndEndTime = mapper.readValue(value, StartAndEndTimeVo.class);
                    long startTime = startAndEndTime.getStartTime();
                    long endTime = startAndEndTime.getEndTime();
                    //与当前时间进行比较
                    if((startTime-nowTime)<=4000 && (nowTime-startTime)<1000){
                        //作业开始时间前4秒到后1秒内 则修改作业开始状态
                        //调用设置作业开始的队列
                        mqTemplate.convertAndSend(SET_TASK_TEST_START_QUEUE,layoutId);
                        log.info("开始设置作业:{}的开始状态",layoutId);
                    }
                    if((endTime-nowTime)<=3000 && (nowTime-endTime)<2000){
                        //作业结束时间前3秒到后2秒内 则修改作业结束状态
                        //调用设置作业结束的队列
                        //同时处理Redis中的数据
                        mqTemplate.convertAndSend(SET_TASK_TEST_END_QUEUE,layoutId);
                        log.info("开始设置作业:{}的结束状态",layoutId);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }


    }


}




